import {
  Directive,
  OnInit,
  Input,
  ElementRef,
  Renderer2,
  ViewContainerRef,
  ComponentFactory,
  ComponentFactoryResolver,
  TemplateRef,
  Output,
  EventEmitter,
  OnChanges,
  SimpleChanges,
  OnDestroy,
  ChangeDetectorRef,
} from '@angular/core';
import { Subject } from 'rxjs';
import { InputBoolean } from '../utils/api';
import { TooltipBaseComponent } from './tooltipbase.component';
import { PositionType, ThemeType, TriggerType } from './interface';

/** @deprecated: 已废弃，popover、tooltip使用自身指令 */
@Directive({
  selector: '[lv-tooltip], [lvTooltip]',
  exportAs: 'lvTooltip',
})
export class TooltipBaseDirective implements OnInit, OnChanges, OnDestroy {
  // 内容图标(tooltip属性)
  @Input() lvIcon: string;
  // overlay样式类
  @Input() lvClassName: string;
  // 主题颜色
  @Input() lvTheme: ThemeType = 'dark';
  // 触发方式
  @Input() lvTrigger: TriggerType = 'hover';
  // 展示位置，默认top，具体设置见POSITION_MAP
  @Input() lvPosition: PositionType = 'top';
  // 控制overlay是否显示,lvTrigger为customize时生效
  @Input() @InputBoolean() lvVisible: boolean;
  // overlay触发源点
  @Input() lvOrigin: ElementRef = this.elementRef;
  // 内容头部(popover属性)
  @Input() lvHeader: string | TemplateRef<void> = null;
  // 内容底部(popover属性)
  @Input() lvFooter: string | TemplateRef<void> = null;
  // 是否禁用(popover属性)
  @Input() @InputBoolean() lvDisabled: boolean = false;
  // 是否显示关闭按钮(popover属性)
  @Input() @InputBoolean() lvClosable: boolean = false;
  // 是否显示遮罩层(popover属性)
  @Input() @InputBoolean() lvBackdrop: boolean = false;
  // 控制overlay小三角是否显示
  @Input() @InputBoolean() lvShowArrow: boolean = true;
  // 内容
  @Input() lvContent: string | TemplateRef<void> = null;
  // overlay动画种类
  @Input() lvAnimationType: 'popup' | 'slide' = 'popup';
  // 遮罩层是否透明(popover属性)
  @Input() @InputBoolean() lvMaskTransparent: boolean = false;
  // 是否锁定页面滚动
  @Input() @InputBoolean() lvBlockPageScroll: boolean = false;
  // 滚动时是否隐藏
  @Input() lvScrollToClose: boolean | { exclusions: HTMLElement[] };
  // 点击overlay外部时是否关闭overlay(popover属性)
  @Input() lvOuterClosable: boolean | { exclusions: HTMLElement[] };
  // 外部触发关闭回调事件
  @Output() lvExternalTrigger: EventEmitter<any> = new EventEmitter();
  // overlay打开后自定义事件
  @Input() lvAfterOpen: () => (false | void | object) | Promise<false | void | object>;
  // overlay打开前自定义事件
  @Input() lvBeforeOpen: () => (false | void | object) | Promise<false | void | object>;
  // overlay关闭后自定义事件
  @Input() lvAfterClose: () => (false | void | object) | Promise<false | void | object>;

  // overlay关闭前自定义事件
  @Input() lvBeforeClose: () => (false | void | object) | Promise<false | void | object>;

  @Output() readonly lvVisibleChange: EventEmitter<boolean> = new EventEmitter();

  tooltip: TooltipBaseComponent;
  /**
   * 用于动态创建组件，
   */
  protected ComponentFactory: ComponentFactory<TooltipBaseComponent>;

  protected needProxyProperties = [
    'lvHeader',
    'lvContent',
    'lvFooter',
    'lvIcon',
    'lvTheme',
    'lvTrigger',
    'lvPosition',
    'lvDisabled',
    'lvClosable',
    'lvBackdrop',
    'lvMaskTransparent',
    'lvScrollToClose',
    'lvOuterClosable',
    'lvClassName',
    'lvVisible',
    'lvShowArrow',
    'lvBeforeOpen',
    'lvAfterOpen',
    'lvBeforeClose',
    'lvAfterClose',
    'lvExternalTrigger',
    'lvVisibleChange',
    'lvAnimationType',
    'lvBlockPageScroll',
    'lvOrigin',
  ];

  private destroy$ = new Subject<void>();

  constructor(
    public elementRef: ElementRef,
    protected renderer: Renderer2,
    protected resolver: ComponentFactoryResolver,
    protected ViewContainer: ViewContainerRef,
    protected cdr: ChangeDetectorRef,
    protected _tooltip?: TooltipBaseComponent,
  ) {}

  show(): void {
    this.tooltip.show();
  }

  hide(): void {
    this.tooltip.hide();
  }

  ngOnDestroy(): void {
    this.destroy$.next();
    this.destroy$.complete();
  }

  /**
   * 让组件更新其位置，用于鼠标移动时，改变tips位置
   */
  updatePosition(): void {
    if (this.tooltip) {
      this.tooltip.updatePosition();
    }
  }

  ngOnInit(): void {
    if (!this._tooltip) {
      this.createTooltipComponent();
    } else {
      this.tooltip = this._tooltip;
    }
  }

  ngOnChanges(changes: SimpleChanges): void {
    Object.keys(changes).forEach((key): void => {
      if (changes[key]) {
        this.updateComponentProperties(key, changes[key].currentValue);
      }
    });

    this.cdr.markForCheck();
  }

  /**
   * 更新directive的属性到component
   */
  private updateComponentProperties(key: string, value: any): void {
    if (value !== null || value !== undefined) {
      if (key !== 'lvVisible' && key !== 'lvPosition') {
        this.tooltip && (this.tooltip[key] = value);
      } else {
        if (key === 'lvVisible') {
          if (this.tooltip && value !== this.tooltip.lvVisible) {
            this.tooltip.visibleChange(value);
          }
        }

        if (key === 'lvPosition') {
          this.tooltip?.positionChange(value);
        }
      }
    }
  }

  /**
   * 创建tooltip组件
   */
  private createTooltipComponent(): void {
    const tooltipRef = this.ViewContainer.createComponent(this.ComponentFactory);
    this.tooltip = tooltipRef.instance;
    this.tooltip.element = this.elementRef.nativeElement;

    // 删除组件的DOM，因为它应该在overlay容器中。
    this.renderer.removeChild(
      this.renderer.parentNode(this.elementRef.nativeElement),
      tooltipRef.location.nativeElement,
    );

    // 更新所有属性到组件
    this.needProxyProperties.forEach((property): void => {
      this.updateComponentProperties(property, this[property]);
    });
  }
}
